home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
007
/
mapmem.arc
/
MAPMEM.PAS
< prev
Wrap
Pascal/Delphi Source File
|
1986-01-24
|
8KB
|
264 lines
{************************************************************************
* maps system memory blocks for MS/PCDOS 2.0 and higher. *
* may work on other versions of DOS but hasn't been tested. *
* copyright (c) 1986 K. Kokkonen, TurboPower Software. *
* released to the public domain for personal, non-commercial use only. *
* written 1/2/86 *
* revised 1/10/86 for *
* running under DOS 2.X, where block owner names are unknown *
* revised 1/22/86 for *
* a bug in parsing the owner name of the block *
* a quirk in the way that the DOS PRINT buffer installs itself *
* minor cosmetic changes *
* telephone: 408-378-3672, CompuServe: 72457,2131. *
* requires Turbo version 3 to compile. *
* BE SURE to compile with mAx dynamic memory = A000. *
* limited to environment sizes of 255 bytes (default is 128 bytes) *
************************************************************************}
PROGRAM MapMem;
{-look at the system memory map using DOS memory control blocks}
CONST
{set the following True to see all of the candidates for memory blocks }
{MapMem filters out some that are uninteresting or unsupported }
showcandidates=False;
midblockid=$4D; {byte DOS uses to identify part of MCB chain}
endblockid=$5A; {byte DOS uses to identify last block of MCB chain}
maxvector=$40; {highest interrupt vector checked for trapping}
TYPE
address=RECORD
offset,segment:Integer;
END;
VAR
dosv:Byte; {the major DOS version number}
mcbseg:Integer; {potential segment address of an MCB}
nextseg:Integer; {computed segment address for the next MCB}
prevseg:Integer; {segment address of the previous PSP}
oldseg:Integer; {segment address of the previous-1 PSP}
pspadd:Integer; {segment address of the current PSP}
mcblen:Integer; {size of the current memory block in paragraphs}
gotfirst:Boolean; {true after first MCB is found}
gotlast:Boolean; {true after last MCB is found}
idbyte:Byte; {byte that DOS uses to identify an MCB}
vectors:ARRAY[0..maxvector] OF address ABSOLUTE 0:0;
FUNCTION DOSversion:Byte;
{-return the major version number of DOS}
VAR
reg:RECORD
CASE Byte OF
1:(ax,bx,cx,dx,bp,si,di,ds,es,flags:Integer);
2:(al,ah,bl,bh,cl,ch,dl,dh:Byte);
END;
BEGIN
reg.ah:=$30;
MsDos(reg);
DOSversion:=reg.al;
END{dosversion};
PROCEDURE ShowTheBlock(VAR mcbseg,prevseg,nextseg:Integer;
VAR gotfirst,gotlast:Boolean);
{-display information regarding the memory block}
TYPE
pathname=STRING[64];
hexstring=STRING[4];
VAR
st:pathname;
FUNCTION Hex(i:Integer):hexstring;
{-return hex representation of integer}
CONST
hc:ARRAY[0..15] OF Char='0123456789ABCDEF';
VAR
l,h:Byte;
BEGIN
l:=Lo(i);h:=Hi(i);
Hex:=hc[h SHR 4]+hc[h AND $F]+hc[l SHR 4]+hc[l AND $F];
END{hex};
FUNCTION Cardinal(i:Integer):Real;
{-return an unsigned integer 0..65535}
VAR
r:Real;
BEGIN
r:=i;
IF r<0 THEN r:=r+65536.0;
Cardinal:=r;
END{cardinal};
FUNCTION Owner(startadd:Integer):pathname;
{-return the name of the owner program of an MCB}
VAR
e:STRING[255];
i:Integer;
t:pathname;
PROCEDURE StripPathname(VAR pname:pathname);
{-remove leading drive or path name from the input}
VAR
spos,cpos,rpos:Byte;
BEGIN
spos:=Pos('\',pname);
cpos:=Pos(':',pname);
IF spos+cpos=0 THEN Exit;
IF spos<>0 THEN BEGIN
{find the last slash in the pathname}
rpos:=Length(pname);
WHILE (rpos>0) AND (pname[rpos]<>'\') DO rpos:=Pred(rpos);
END ELSE
rpos:=cpos;
Delete(pname,1,rpos);
END{strippathname};
BEGIN
{get the environment string to scan}
e[0]:=#255;
Move(Mem[startadd:0],e[1],255);
{find end of the standard environment}
i:=Pos(#0#0,e);
IF i=0 THEN BEGIN
{something's wrong, exit gracefully}
Owner:='';
Exit;
END;
{end of environment found, get the program name that follows it}
t:='';
i:=i+3; {skip over #0#0#args}
REPEAT
t:=t+Chr(Mem[startadd:i]);
i:=Succ(i);
UNTIL Mem[startadd:i]=0;
StripPathname(t);
Owner:=t;
END; {owner}
PROCEDURE WriteHooks(start,stop:Integer);
{-show the trapped interrupt vectors}
VAR
v:Byte;
vadd,sadd,eadd:Real;
FUNCTION RealAdd(a:address):Real;
{-return the real equivalent of an address (pointer)}
BEGIN
WITH a DO
RealAdd:=16.0*Cardinal(segment)+Cardinal(offset);
END{realadd};
BEGIN
sadd:=16.0*Cardinal(start);
eadd:=16.0*Cardinal(stop);
FOR v:=0 TO maxvector DO BEGIN
vadd:=RealAdd(vectors[v]);
IF (vadd>=sadd) AND (vadd<=eadd) THEN
Write(Copy(Hex(v),3,2),' ');
END;
END{writehooks};
PROCEDURE writemost;
{-write most of the information about the memory block}
BEGIN
{.F-}
Write(' ',
Hex(mcbseg), ' ', {MCB address}
Hex(pspadd), ' ', {PSP address}
Hex(mcblen), ' ', {size of block in paragraphs}
16.0*Cardinal(mcblen):6:0, ' '); {size of block in bytes}
{.F+}
{get the program owning this block by scanning the environment}
IF gotfirst THEN
IF dosv>=3 THEN
st:=Owner(MemW[pspadd:$2C])
ELSE
st:='N/A'
ELSE
st:='(DOS)';
WHILE Length(st)<13 DO st:=st+' ';
Write(st);
END{writemost};
PROCEDURE QueueSegs(pspadd:Integer;VAR prevseg,oldseg:Integer);
{-push the PSP segments back through a 2 deep queue}
BEGIN
oldseg:=prevseg;
prevseg:=pspadd;
END{queuesegs};
BEGIN {showtheblock}
mcblen:=MemW[mcbseg:3];{size of the MCB in paragraphs}
nextseg:=Succ(mcbseg+mcblen);{where the next MCB should be}
pspadd:=MemW[mcbseg:1];{address of program segment prefix for MCB}
IF showcandidates THEN BEGIN
{show all potential MCBs without filtering techniques we employ below}
LowVideo;
writemost;
Write(' ',Hex(nextseg),' ',Hex(Mem[nextseg:0]),' ');
WriteLn;
highvideo;
END;
IF (gotlast OR (Mem[nextseg:0]=$4D)) AND (pspadd<>0) THEN BEGIN
{found part of MCB chain}
IF gotlast OR (pspadd=prevseg) OR (pspadd=oldseg) THEN BEGIN
{this is the MCB for the program, not for its environment}
writemost;
{show any interrupt vectors trapped by the program}
IF gotfirst THEN WriteHooks(pspadd,nextseg);
WriteLn;
gotfirst:=True;
END;
QueueSegs(pspadd,prevseg,oldseg);
END;
END{showtheblock};
BEGIN {main}
WriteLn;
WriteLn(' Allocated Memory Map');
WriteLn;
WriteLn('MCB adr PSP adr paras bytes owner hooked vectors');
WriteLn('------- ------- ------- ------- ---------- ------------------------------');
{start above the Basic work area, could probably start even higher}
{there must be a magic address to start from, but it is not documented}
mcbseg:=$50;
prevseg:=0;
oldseg:=0;
gotfirst:=False;
gotlast:=False;
dosv:=DOSversion;
{scan all memory until the last block is found}
WHILE mcbseg<>$A000 DO BEGIN
idbyte:=Mem[mcbseg:0];
IF idbyte=midblockid THEN BEGIN
{an allocated block}
ShowTheBlock(mcbseg,prevseg,nextseg,gotfirst,gotlast);
{search every paragraph boundary until first block is found}
{then chain directly from block to block}
IF gotfirst THEN mcbseg:=nextseg ELSE mcbseg:=Succ(mcbseg);
END ELSE IF (idbyte=endblockid) AND gotfirst THEN BEGIN
{last block, exit}
gotlast:=True;
ShowTheBlock(mcbseg,prevseg,nextseg,gotfirst,gotlast);
mcbseg:=$A000;
END ELSE
{still looking for first block, try every paragraph boundary}
mcbseg:=Succ(mcbseg);
END;
END.